The layout for project and source files has changed since d11. Sample parts now keep all their source files in one folder, called “Sources”, instead of dividing them into Sources, Include, and Other. The sample part folders are now inside the ODFDev folder, at the same level as the ODF folder. Each sample part folder contains a set of build folders for different build configurations - CWPPCDebug for Code Warrior PowerPC debug build, SC68KRelease for Symantec 68K non-debug build, etc. After building, the resulting part and sym files are located in the corresponding build folder. (Make an alias to the part file and place the alias in the Editors folder on the same disk, so that OpenDoc can find it.)
Source Files
ODF uses these conventions for part source files:
• Resource files (.fr suffix means a cross-platform resource file):
Menus.fr - menu and string resources
PartInfo.fr - PartInfo and About resources
Views.fr - view resources
Part.r - Mac-specific resources like 'cfrg' and nmaps
• Files containing #defines that are used in both C++ and resource files have the suffix “.k”.
Binding.k contains definitions used in Part.r and Part.cpp - part kind string, editor string, etc.
Defines.k contains definitions used in .fr files - resource IDs, command IDs, etc.
In order to follow these conventions, you should discard your MyPartDef.h file and move its definitions into Binding.k and Defines.k files. You may also want to convert your menu and view creation code to resources. See the section “Resources” below.
Code Warrior Projects
Code Warrior project files in ODF 1 are in CW8 format. To update your old CW7 project file, open it with CW8 and perform the following adjustments (debug version assumed):
• Add the shared library, ODFLibrary (located in the Bin folder of SLPPCDebug)
• Remove ODF .rsrc files such as FWOSMisc.rsrc (resources are now in the shared library)
• Remove your part’s .rsrc files and add .r and .fr files (they can now be built using plug-ins)
• In Preferences, change the access paths to look like this:
{Project ƒ}:
{Project ƒ}::Sources:
{Project ƒ}:::ODF:Found:
{Project ƒ}:::ODF:OS:
{Project ƒ}:::ODF:Framewrk:
{Project ƒ}:::ODF:CWPPCDebug:
{Project ƒ}:::ODF:SLPPCDebug:
---
{Project ƒ}:::ODF:Found:ODUtils:Include:
{Compiler ƒ}:MacOS Support:Headers:
{Compiler ƒ}:MacOS Support:Libraries:
{Compiler ƒ}:MacOS Support:MacHeaders:
Part API
The FW_CPart constructor API has changed. Formerly each part had static members for the part kind and user name strings. These strings have been moved into resources, so you can remove the data members kPartKind and kPartUserName from your part class definition. Also remove the static initialization statements from your Part.cpp file. Instead of taking the part kind, part user name, and icon id, the FW_CPart constructor now takes the id of a PartInfo resource.
Normally you supply the PartInfo resource in the PartInfo.fr file:
resource FW_RPartInfo(kPartInfoID)
{
// ----- Icon ID
kMyIconID,
// ----- Part Name
kMyEditorUserString,
// ----- PartKind
kMyPartKind
};
See the Engineering note “Part Info Resource” for more details on this resource.
Part (Content Model)
There have been major changes to the way a part handles its data. ODF now has what we call the Content Model, in which persistent data is managed by Content objects (derived from FW_CContent). Part data is defined in a CPartContent class instead of in the part class. The part keeps a pointer to its part content object so that operations like internalizing and externalizing can be delegated to it.
Here is an outline of the steps to convert your part and its data to the new content model:
- Make new files Content.h/.cpp.
- Define CMyPartContent, which is a subclass of FW_CContent or FW_CEmbeddingContent.
- Remove all persistent data from the part class and move it into CMyPartContent.
- Override FW_CPart::NewPartContent to create and return an instance of CMyPartContent.
- Override these FW_CContent methods:
Externalize - move code from ExternalizeContent (you can remove the code to Focus/Remove/AddValue to the storage unit; ODF takes care of this for you in FW_CPart::ClearPartStorage)
Internalize - move code from InternalizeContent
- (Embedding parts) Override these FW_CEmbeddingContent methods:
IsDataOnlyOneProxy - move code from IsSelectionOnlyOneProxy
See the Engineering Note “Content Model” for more recipes and diagrams.
Also see the section “Defining your Part’s Content Object” on p.45 of the ODF Developer’s Guide.
Selection (Content Model)
There have been massive changes to the way the selection handles its data, internalizes, and externalizes. Like part data, selection data is now kept in a content object to which in/externalize operations are delegated. The class FW_CEmbeddingSelection no longer exists, its role has been taken over by FW_CEmbeddingContent and other classes.
Here is an outline of the steps to convert your selection and its data to the content model:
- Define CMySelectionContent, which is a subclass of FW_CContent or FW_CEmbeddingContent
- Remove all persistent data from the selection class and move it into CMySelectionContent
- Override FW_CSelection::GetSelectedContent to return a pointer to the CMySelectionContent object
- Override these FW_CContent methods:
Externalize - move code from DoExternalizeSelection
Internalize - move code from DoInternalizeSelection
CreateDataFrameShape - move code from CreateSelectionFrameShape
- (Embedding parts) Override these FW_CEmbeddingContent methods:
IsDataOnlyOneProxy - adapt code from IsSelectionOnlyOneProxy
SingleEmbeddedFrameInternalized - adapt code from CMyFrame::EmbedSingleFrame
- (Embedding parts) CMySelection should be derived from FW_CSelection, since FW_CEmbeddingSelection is gone
- Remove these methods from CMySelection:
DoExternalizeSelection
DoInternalizeSelection
IsSelectionOnlyOneProxy
CreateSelectionFrameShape
InsertNewPart - this is now handled by the Insert command (see below)
See the Engineering Note “Content Model” for more recipes and diagrams.
Commands
The clipboard and drag and drop commands still use the selection object for internalizing and externalizing. However, the content object has taken over the role of managing the data.
• Call cmd->Execute(ev) instead of part->ExecuteCommand(ev, cmd);
• All the fields of FW_CCommand are now private, so you’ll have to use inline accessors:
fCommandID GetCommandID(ev)
fFrame GetFrame(ev)
fPart GetPart(ev)
• The field fSelection has been removed from FW_CCommand, and added to the commands that use it: FW_CClipboardCommand, FW_CDragCommand, and FW_CDropCommand.
Edit Commands
FW_CEditCommand has been renamed to FW_CClipboardCommand. It still handles the same menu commands: Cut, Copy, Paste, Paste As, Clear, Select All.
• The following methods were removed:
DoClear
DoCut
DoPaste
DoPasteAs
If you overrode any of these methods in d11, move the code into CommandDone. CommandDone is called after the operation has been successfully completed. There is a new method PreCommand, which is called before the operation is done. You might want to override PreCommand to close your selection before a Paste, for example.
• You no longer need to call SetMenuStrings. ODF sets the undo strings to default values for clipboard commands.
Drag and Drop
In the d11 version of ODF, drag and drop support was automatically available to all frames because FW_MDragDroppable was mixed into FW_CFrame. In ODF 1 the class FW_MDragDroppable has been split into two mixin classes, FW_MDraggableFrame and FW_MDroppableFrame. If you want your frame to support dragging and/or dropping, you must specify it yourself as described below. It’s a little bit more flexible in that your frame can support dropping without dragging, and vice-versa.
• If your frame has draggable content, do the following:
mixin FW_MDraggableFrame
override FW_CSelection::IsMouseInDraggableItem if desired (unchanged from d11)
• If your frame supports dropping, do the following:
mixin FW_MDroppableFrame
override FW_CFrame::CanAcceptDrop
remove call to SetDroppable, since the FW_MDroppableFrame constructor calls it
Undo strings are set automatically to defaults, so you can remove SetMenuStrings calls from your command constructors.
Embedding
The following virtual methods were removed from ODF:
Functionality moved to FW_CInsertCommand (see next section)
See the documents in the Embedding folder of the Engineering Notes.
Insert Command
The Insert menu command is now handled by the ODF class FW_CInsertCommand. The inserted part will be added to your selection’s content object. If you want this command to be undoable (strongly recommended), you must subclass it and provide appropriate UndoIt and RedoIt methods. FW_CEmbeddingFrame defines a factory method which you must override to create your subclass of FW_CInsertCommand. For example, from the Draw sample:
Changes to Graphics for moving the code to the shared library:
• The classes listed below have been moved to the SL using a "handle/wrapper" technique: There is an opaque "handle" data type and a set of APIs exported from the SL that create/destroy/manipulate the handle. Then there is a C++ wrapper class that owns a handle of that type, and contains inline methods that simply delegate to the appropriate exported SL APIs.
FW_PInk FW_PStyle FW_PPattern
FW_PFont FW_PBitmap FW_PPicture
FW_PIcon FW_PPolygon
In each case, the handle type wrapped by a C++ class FW_Pxxx is FW_Hxxx, so FW_PIcon wraps FW_HIcon, FW_PFont wraps FW_HFont, etc.
These classes used to be smart pointer classes that overloaded operator->() to implement delegation to the "Rep" object. Thus their methods were called like: "font-> SetFontName(name)". With the new approach, the delegation is done using inlines (as described above), so the normal method-calling syntax should be used, as in "font.SetFontName(name)".
• FW_CGraphicDevice is only exported as an opaque handle type, FW_HGDevice.
• FW_CMapping and FW_CGraphicContext have been split into a private structure (FW_SMapping and FW_SGraphicsContext, respectively) and a C++ subclass with wrapper functions. The structures should not be used directly, use the C++ wrappers instead.
• Removed FW_CRasterizer class. This should not affect your code unless you call its methods directly. You can use functions in SLRender.h to render without creating shapes, but the preferred way to do this is to use static methods of various shape classes, as in "FW_CRectShape::RenderRect(gc, rect, FW_kFrame);"
• Changed global color constants from "const FW_CColor" to "const FW_SColor"
• Fixed point math: instead of a class, FW_CFixed, with operators defined as members, there is now a struct, FW_Fixed, with operators defined in the global scope. This was done because we can't pass C++ objects across SOM boundaries, only plain C data types and simple structs made from them.
This means that you can't use member functions of FW_CFixed anymore. For example, you will need to change:
fx.Half() FW_Half(fx)
fx.DividedByInt(n) FW_DividedByInt(fx, n)
fx.RoundedToInt() FW_RoundedToInt(fx)
fx.Sin() FW_Sin(fx)
The same goes for the FW_CWide class: it's been "struct"-ified into FW_Wide.
See the chapter on Graphics in the ODF Developer’s Guide.
Linking
Linking has undergone a massive renaming. See the text file ODF API Changes for a long list of class and method names that have changed. Basically, the term “Publish” was replaced with “LinkSource” and the term “Subscribe” was replaced with “LinkDestination”. The methods called “Publish” and “Subscribe” have been renamed to “LinkEstablished” to more accurately reflect their purpose.
Linking has also undergone some restructuring. There is a new base class for both link sources and destinations. This class (FW_CLink) provides the API for link borders and selection, although support for these features is still incomplete in ODF.
There is more support for in/externalizing persistent links in ODF1, mostly in the class FW_CLinkManager. The method GetPublishFormat has been moved to FW_CLinkManager and renamed to GetSourceLinkFormat. It has a companion method GetDestLinkFormat which must also be overridden, since the value strings for source and destination links must be different. FW_CLinkManager now has six methods that must be overridden. Besides the format string functions there are the original two, NewLinkSource and NewLinkDestination (formerly called NewPublishLink and NewSubscribeLink). And finally, there are two methods for internalizing links from a storage unit, DoInternalizeOneSourceLink and DoInternalizeOneDestLink.
See the sample parts Draw and Table for examples of linking.
Menus
In FW_CPulldownMenu, all methods for adding menu items using string resources have been removed:
AppendTextItem
AppendToggleItem
InsertTextItem, InsertTextItemAfterCommand
InsertToggleItem, InsertToggleItemAfterCommand
You can now define your menus in resources. For example, in the d11 version of the Hello sample each menu and menu item had to be created individually:
FW_CPullDownMenu* pullDownMenu = new FW_CPullDownMenu(ev, resFile, kHelloPartStrings, kHelloMenuString);
Notification has been simplified. The class FW_CConnection has been removed and its functionality has been rolled into FW_MReceiver. There are now only four classes involved in notification: FW_MReceiver, FW_MNotifier, FW_CInterest, and FW_CNotification.
FW_CInterest API changes:
Instead of FW_TypeToken fName, uses FW_Message fMessage to describe the type of notification.
Constructor parameter change (FW_TypeToken name replaced by FW_Message msg).
GetName (returned an FW_TypeToken) replaced by GetMessage (returns an FW_Message)
FW_CNotification API changes:
GetName (returned an FW_TypeToken) replaced by GetMessage (returns an FW_Message)
new method SetInterest
FW_MNotifier API changes:
Notify method takes an ev parameter
AddConnection renamed to AddReceiver; 1st param is an FW_MReceiver instead of an FW_CConnection
RemoveConnection renamed to RemoveReceiver; 1st param change as above
new method IsConnectedTo
FW_MReceiver API changes:
HandleNotification method takes an ev parameter
added methods from defunct FW_CConnection: RemoveAllInterests, RemoveInterest, Connect, Disconnect, IsConnected
new methods AddInterest, AddNotifier, RemoveNotifier
Other API changes:
FW_CFrame::AddConnection is gone; use FW_MReceiver::AddInterest instead.
All notifiers now send a FW_kNotifierDeletedMsg message in their destructor to let their receivers know that they are going away. This is used for example by FW_CRadioCluster objects which delete themselves after the last radio button has been deleted.
See the Engineering Note “Notification” for details and sample code.
Promises
Promises are no longer handled by FW_CPart. Members related to promises have been moved to the class FW_CDataInterchange.
FW_CSelection::NewPromise is gone. Override FW_CContent::Externalize and create the promise(s) there. Then call aPromise->Promise(ev, storageUnit, property, value) for each promise.
FW_CPart::GetPromise is also gone. ODF’s data interchange object keeps track of promises created for clipboard commands, drag and drop, and linking. If you need to access a promise, save a reference to it when you create it.
See the Engineering Note “Promises” for sample code.
Resources
ODF 1 enables you to define menus, views, and About boxes in resources. By convention cross-platform resource definitions are kept in files with the suffix “.fr”. These files are compiled by ODFRC, ODF’s cross-platform resource compiler.
About Box resource
To display the About box in response to a kODCommandAbout command, call the global method FW_About and pass it your part and the id of your About resource. Note that the About item in the Apple menu is automatically set by ODF to contain your part's name. You do not need to set it up in DoAdjustMenus.
See the Engineering Note “About Box” for sample code.
Menu resources
Menus can now be defined in resources. You can remove all of your menu setup code in CMyPart::Initialize and replace it with one line:
See the Engineering Note “Menu Resources” for samples.
Part Info resource
This is a new resource required in ODF 1. It contains some information that was previously defined in static part members and passed to the FW_CPart constructor. The section “Part API” above tells how to convert this data.
See the Engineering Note “Part Info Resource” for more information.
View resources
Views can now be defined in resources. You can remove all of your view creation code in CMyFrame::CreateSubViews and replace it with one line:
Make sure that view classes created from resources won't be dead-stripped by the linker. Use the macro FW_DO_NOT_DEAD_STRIP for those classes which are not referenced anywhere else in your part's code. Here is an example from the Form sample part:
FW_DO_NOT_DEAD_STRIP(FW_CGrowBox);
See the Engineering Note “Defining Views in Resources” .
Views
The hierarchy of view classes has changed a lot. The new class FW_CSuperView represents a view that can contain subviews. The class FW_CGadget has been renamed to FW_CControl, and there are many new classes representing controls. There is a simple view layout management system based on six bindings between a view and its parent view. This is described in the Engineering Note “Layout Management”.
Old hierarchy:
FW_CView
FW_CFrame
FW_CEmbeddingFrame
FW_CGadget
FW_CButton (Notifier)
FW_CPushButton
FW_CRadioButton
FW_CGrowBox
FW_CRadioCluster (Receiver)
FW_CScrollBar (Notifier)
New hierarchy:
FW_CView
FW_CSuperView (new)
FW_CFrame
FW_CDialogFrame (new)
FW_CAboutFrame (new)
FW_CEmbeddingFrame
FW_CControl (Notifier)
FW_CNativeControl (new)
FW_CButton (4 kinds, including radio and checkbox)
FW_CPopupMenu (new)
FW_CScrollBar
FW_CEditView (new; Notifier)
FW_CGrowBox
FW_CListBox (new; Notifier)
FW_CStaticText (new)
FW_CGroupBox (new)
FW_CRadioCluster is now a subclass of FW_MReceiver only; it’s no longer a View.
• FW_CFrame::AdjustSubViews was renamed AdjustSubViewsLayout. You need to override it only if your part requires a layout scheme that is more complex than the simple “6-binding” one provided by ODF. There is also a new method AdjustToNewLayout that should be overridden if the view cannot be resized using just binding flags. See the samples Form and Draw where the content view requires special processing.
• The classes FW_CRadioButton and FW_CPushButton have been merged into a single class, FW_CButton. FW_CButton has a "kind" field which tells whether it’s a push-button, radio button, or checkbox.
For more information on what has changed in views, see”Managing your Part’s Interface” in the ODF Developer’s Guide Update. Also see the various documents in the Views folder of Engineering Notes.